package my.suveng.oauth2.service.user.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.querydsl.core.QueryResults;
import com.querydsl.jpa.impl.JPAQueryFactory;
import my.suveng.model.common.interfaces.response.IMessage;
import my.suveng.model.common.response.Message;
import my.suveng.model.common.response.element.ElementPage;
import my.suveng.model.common.response.element.PageQuery;
import my.suveng.oauth2.model.dto.GroupAddRoleDto;
import my.suveng.oauth2.model.dto.GroupDeleteDto;
import my.suveng.oauth2.model.dto.GroupEditDto;
import my.suveng.oauth2.model.dto.GroupSearch;
import my.suveng.oauth2.service.auth.impl.AuthServiceImpl;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysGroupRepository;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysGroupRoleRepository;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysUserGroupRepository;
import my.suveng.oauth2.service.db.mysql.model.entity.*;
import my.suveng.oauth2.service.user.IGroupService;
import my.suveng.util.log.PlusLogFactoryHutool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * @author suwenguang
 **/
@Service
public class GroupServiceImpl implements IGroupService {

    // hutool日志
    private static final Log log = LogFactory.setCurrentLogFactory(new PlusLogFactoryHutool())
            .getLog(CallerUtil.getCaller().getName());

    @Autowired
    private SysGroupRepository sysGroupRepository;

    @Autowired
    private JPAQueryFactory jpaQueryFactory;

    @Autowired
    private AuthServiceImpl authService;

    @Autowired
    private SysGroupRoleRepository sysGroupRoleRepository;

    @Autowired
    private SysUserGroupRepository sysUserGroupRepository;

    /**
     * 获取组列表 多条件搜索
     *
     * @author suwenguang
     */
    public IMessage<ElementPage<List<SysGroup>>> groupList(PageQuery<GroupSearch> query) {
        Specification<SysGroup> specification = buildSpecification(query);
        Sort.Order order = query.order();

        Page<SysGroup> page;
        Specification<SysGroup> where = Specification.where(specification);

        if (ObjectUtil.isEmpty(order)) {
            page = sysGroupRepository.findAll(where, PageRequest.of(query.getCurrentPage() - 1, query.getPageSize()));
        } else {
            Sort sort = Sort.by(order);
            page = sysGroupRepository.findAll(where,
                    PageRequest.of(query.getCurrentPage() - 1, query.getPageSize(), sort));
        }

        return ElementPage.build(page.getTotalElements(), page.getContent());
    }

    /**
     * 动态构造查询参数
     *
     * @author suwenguang
     */
    private Specification<SysGroup> buildSpecification(PageQuery<GroupSearch> query) {
        if (ObjectUtil.isEmpty(query) || ObjectUtil.isEmpty(query.getSearch())) {
            return null;
        }

        GroupSearch search = query.getSearch();

        return new Specification<SysGroup>() {
            @Override
            public Predicate toPredicate(Root<SysGroup> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<>();

                if (ObjectUtil.isNotEmpty(search.getId())) {
                    list.add(criteriaBuilder.equal(root.get("id").as(Long.class), search.getId()));
                }

                // name模糊查询
                if (StrUtil.isNotBlank(search.getName())) {
                    list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + search.getName() + "%"));
                }
                if (ObjectUtil.isNotEmpty(search.getParentId())) {
                    list.add(criteriaBuilder.equal(root.get("parentId").as(Long.class), search.getParentId()));
                }
                if (ObjectUtil.isNotEmpty(search.getLevel())) {
                    list.add(criteriaBuilder.equal(root.get("level").as(Long.class), search.getLevel()));
                }
                if (ObjectUtil.isNotEmpty(search.getMasterId())) {
                    list.add(criteriaBuilder.equal(root.get("masterId").as(Long.class), search.getMasterId()));
                }

                if (ObjectUtil.isNotEmpty(search.getCreator())) {
                    list.add(criteriaBuilder.equal(root.get("creator").as(Long.class), search.getCreator()));
                }

                if (ObjectUtil.isNotEmpty(search.getUpdator())) {
                    list.add(criteriaBuilder.equal(root.get("updator").as(Long.class), search.getUpdator()));
                }

                if (ObjectUtil.isNotEmpty(search.getStatus())) {
                    list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), search.getStatus()));
                }

                // 时间
                if (StrUtil.isNotBlank(search.getCreateTimeStart())) {
                    list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(String.class),
                            search.getCreateTimeStart()));

                }
                if (StrUtil.isNotBlank(search.getCreateTimeEnd())) {
                    list.add(criteriaBuilder.lessThan(root.get("createTime").as(String.class),
                            search.getCreateTimeEnd()));
                }

                // 时间
                if (StrUtil.isNotBlank(search.getModifyTimeStart())) {
                    list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("modifyTime").as(String.class),
                            search.getModifyTimeStart()));
                }
                if (StrUtil.isNotBlank(search.getModifyTimeEnd())) {
                    list.add(criteriaBuilder.lessThan(root.get("modifyTime").as(String.class),
                            search.getModifyTimeEnd()));
                }

                Predicate[] p = new Predicate[list.size()];

                return criteriaBuilder.and(list.toArray(p));
            }
        };
    }

    /**
     * 修改用户组信息
     *
     * @author suwenguang
     */
    public IMessage<SysGroup> edit(GroupEditDto groupEditDto) {
        // 查询记录
        SysGroup oldRecord = jpaQueryFactory.selectFrom(QSysGroup.sysGroup)
                .where(QSysGroup.sysGroup.id.eq(groupEditDto.getId())).fetchOne();
        if (ObjectUtil.isEmpty(oldRecord)) {
            log.info("MySQL记录不存在,id={}", groupEditDto.getId());
            return Message.error("MySQL记录不存在");
        }

        // 修改记录
        oldRecord.setName(groupEditDto.getName());
        SysUser user = authService.getSysUser();
        if (ObjectUtil.isNotEmpty(user)) {
            log.info("用户不存在");
            return Message.error("用户不存在");
        }

        oldRecord.setUpdator(user.getId());
        oldRecord.setModifyTime(new Date());

        SysGroup newGroup = sysGroupRepository.save(oldRecord);

        return Message.successWithData(newGroup);
    }

    /**
     * 删除用户组信息
     *
     * @author suwenguang
     */
    public IMessage<Object> delete(GroupDeleteDto groupDeleteDto) {
        // 物理删除

        // 删除group-role关系
        QSysGroupRole qSysGroupRole = QSysGroupRole.sysGroupRole;
        QueryResults<SysGroupRole> sysGroupRoleQueryResults = jpaQueryFactory.selectFrom(qSysGroupRole)
                .where(qSysGroupRole.groupId.eq(groupDeleteDto.getId())).fetchResults();
        List<SysGroupRole> sysGroupRoleList = sysGroupRoleQueryResults.getResults();
        if (CollUtil.isNotEmpty(sysGroupRoleList)) {
            sysGroupRoleList.forEach(e -> {
                sysGroupRoleRepository.deleteById(e.getId());
            });
        }

        // 删除group-user关系
        QSysUserGroup qSysUserGroup = QSysUserGroup.sysUserGroup;
        QueryResults<SysUserGroup> sysUserGroupQueryResults = jpaQueryFactory.selectFrom(qSysUserGroup)
                .where(qSysUserGroup.groupId.eq(groupDeleteDto.getId())).fetchResults();
        List<SysUserGroup> sysUserGroupList = sysUserGroupQueryResults.getResults();
        if (CollUtil.isNotEmpty(sysUserGroupList)) {
            sysUserGroupList.forEach(e -> {
                sysUserGroupRepository.deleteById(e.getId());
            });
        }

        // 删除group记录
        sysGroupRepository.deleteById(groupDeleteDto.getId());
        return Message.success();
    }

    /**
     * 批量授予组角色
     *
     * @author suwenguang
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public IMessage<List<SysGroupRole>> addRole(GroupAddRoleDto groupAddRoleDto) {
        ArrayList<SysGroupRole> result = new ArrayList<>();
        List<Long> roleIds = groupAddRoleDto.getRoleIds();
        if (CollUtil.isNotEmpty(roleIds)) {
            for (Long roleId : roleIds) {
                IMessage<SysGroupRole> sysGroupRoleMessage = addRole(groupAddRoleDto.getId(), roleId);
                if (!sysGroupRoleMessage.isSuccess()) {
                    throw new RuntimeException("事务异常");
                }

                result.add(sysGroupRoleMessage.getData());
            }
        }

        return Message.successWithData(result);
    }

    /**
     * 组-角色关系
     *
     * @author suwenguang
     */
    private IMessage<SysGroupRole> addRole(Long groupId, Long roleId) {
        // 检查组
        QSysGroup qSysGroup = QSysGroup.sysGroup;
        SysGroup sysGroup = jpaQueryFactory.selectFrom(qSysGroup).where(qSysGroup.id.eq(groupId)).fetchOne();
        if (ObjectUtil.isEmpty(sysGroup)) {
            log.info("组信息不存在,groupId={}", groupId);
            return Message.error("组信息不存在");
        }
        // 检查角色
        QSysRole qSysRole = QSysRole.sysRole;
        SysRole sysRole = jpaQueryFactory.selectFrom(qSysRole).where(qSysRole.id.eq(roleId)).fetchOne();
        if (ObjectUtil.isEmpty(sysRole)) {
            log.info("角色信息不存在,roleId={}", roleId);
            return Message.error("角色信息不存在");
        }

        // 插入组-角色关系
        SysGroupRole entity = new SysGroupRole();
        entity.setGroupId(groupId);
        entity.setRoleId(roleId);

        SysUser sysUser = authService.getSysUser();
        if (ObjectUtil.isEmpty(sysUser)) {
            log.info("token用户不存在");
            return Message.error("token用户不存在");
        }

        entity.setCreator(sysUser.getId());
        entity.setUpdator(sysUser.getId());
        entity.setCreateTime(new Date());
        entity.setModifyTime(new Date());

        SysGroupRole save = sysGroupRoleRepository.save(entity);
        if (ObjectUtil.isEmpty(save.getId())) {
            log.info("group-role入库失败,record={}", JSON.toJSONString(save));
            return Message.error("group-role入库失败");
        }
        return Message.successWithData(save);
    }
}
